package com.gitee.wsl.struct.generator

import kotlin.math.exp
import kotlin.math.ln
import kotlin.math.sqrt
import kotlin.random.Random
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid

typealias RandomGenerator = DoubleGenerator

@OptIn(ExperimentalUuidApi::class)
fun randomUUID() = Uuid.random().toString()

 fun Random.uniform(min: Double = .0, max: Double = 1.0): RandomGenerator = { nextDouble() * (max - min) + min }
 fun Random.bates(n: Double = 1.0): RandomGenerator = { irwinHall(n)() / n }
 fun Random.logNormal(mu: Double = .0, sigma: Double = 1.0): RandomGenerator = { exp(normal(mu, sigma)()) }
 fun Random.exponential(lambda: Double = 1.0): RandomGenerator = { -ln(1 - nextDouble()) / lambda }
 fun Random.irwinHall(n: Double): RandomGenerator = {
    var sum = 0.0
    (0 until n.toInt()).forEach { _ ->
        sum += nextDouble()
    }
    sum
}

 fun Random.normal(mu: Double = .0, sigma: Double = 1.0): RandomGenerator = {
    var x: Double? = null
    var r = 0.0
    var y = 0.0

    if (x != null) {
        y = x
    } else {
        while (r == 0.0 || r > 1) {
            x = nextDouble() * 2 - 1
            y = nextDouble() * 2 - 1
            r = x * x + y * y
        }
    }
    mu + sigma * y * sqrt(-2 * ln(r) / r)
}

fun Random.nextString(length:Int,generatorWithLength: StringGeneratorWithLength) = generatorWithLength(length)